﻿#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    init();//调用初始化函数
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::init()
{
    m_getSize = 0;

    ui->editTargetAddress->setEnabled(false);//默认为服务器,禁用目标地址输入框

//    m_timer1 = new QTimer;
    m_outTime = 5000;//默认客户端连接超时时间5000ms
    m_timer1.setInterval(m_outTime);


    //自动查找与本机绑定的ipv4地址
    QList<QHostAddress> addresses = QHostInfo::fromName(QHostInfo::localHostName()).addresses();
    for(int i = 0; i < addresses.count();++i){
        if(addresses.at(i).protocol() == QAbstractSocket::IPv4Protocol){
            ui->combHostAddress->addItem(addresses.at(i).toString());
        }
    }

    ui->editSavePath->setText(QCoreApplication::applicationDirPath());//设置默认保存路径

    //实例化监听对象和套接字
    m_tcpServer = new QTcpServer(this);
    m_tcpSocket = new QTcpSocket(this);
    connect(m_tcpServer,SIGNAL(newConnection()),this,SLOT(onNewConnection()));
    connect(m_tcpServer,SIGNAL(acceptError(QAbstractSocket::SocketError)),this,SLOT(onTcpServerError(QAbstractSocket::SocketError)));
    connect(m_tcpSocket,SIGNAL(errorOccurred(QAbstractSocket::SocketError)),this,SLOT(onTcpSocketError()));
    connect(m_tcpSocket,SIGNAL(connected()),this,SLOT(onTcpSocketConnected()));
    connect(&m_timer1,SIGNAL(timeout()),this,SLOT(onTime1Out()));
    connect(m_tcpSocket,SIGNAL(readyRead()),this,SLOT(onReadyRead()));
}

void MainWindow::onNewConnection()
{
    if(m_tcpServer->hasPendingConnections()){
        m_tcpSocket = m_tcpServer->nextPendingConnection();
        if(m_tcpSocket->isOpen()){
            ui->textLog->append(m_tcpSocket->peerAddress().toString()+":"+QString::asprintf("%d",m_tcpSocket->peerPort())+"已连接.");
            connect(m_tcpSocket,SIGNAL(readyRead()),this,SLOT(onReadyRead()));

        }else{
            QMessageBox::warning(0,"警告","有用户尝试连接本机,但出现意料之外的错误.");
        }
    }
}

void MainWindow::onTcpServerError(QAbstractSocket::SocketError)
{
    qDebug()<<"QTtcpServer error:"<<m_tcpServer->errorString();
}

void MainWindow::onTcpSocketError()
{
    qDebug()<<"QTcpSocket error:"<<m_tcpSocket->errorString();
}

void MainWindow::onTcpSocketConnected()
{
    if(ui->btnListen->text() == "正在连接"){
        m_timer1.stop();
        ui->btnListen->setEnabled(true);
        ui->btnListen->setText("断开连接");
        ui->textLog->append("连接成功.");
        connect(m_tcpSocket,SIGNAL(readyRead()),this,SLOT(onReadyRead()));
    }
}

void MainWindow::onTime1Out()
{
    m_timer1.stop();
    m_tcpSocket->abort();
    ui->combHostType->setEnabled(true);
    ui->editTargetAddress->setEnabled(true);
    ui->spinPort->setEnabled(true);

    ui->btnListen->setEnabled(true);
    ui->btnListen->setText("连接服务器");

    ui->textLog->append("连接超时...");

}


void MainWindow::on_combHostType_currentIndexChanged(int index)
{
    if(index == 0){//作为服务器
        ui->editTargetAddress->setEnabled(false);
        ui->combHostAddress->setEnabled(true);
        ui->btnListen->setText("开启监听");
    }else if(index == 1){//作为客户端
        ui->editTargetAddress->setEnabled(true);
        ui->combHostAddress->setEnabled(false);
        ui->btnListen->setText("连接服务器");
    }
}


void MainWindow::on_btnListen_clicked()
{
    if(ui->btnListen->text() == "开启监听"){//如果作为服务器且未打开监听
        if(m_tcpServer->listen(QHostAddress(ui->combHostAddress->currentText()),ui->spinPort->value())){//如果监听成功
            ui->textLog->append("已打开监听:"+m_tcpServer->serverAddress().toString()+":"+QString::asprintf("%d",m_tcpServer->serverPort()));

            ui->combHostType->setEnabled(false);
            ui->combHostAddress->setEnabled(false);
            ui->spinPort->setEnabled(false);
            ui->btnListen->setText("关闭监听");
        }else{
            QMessageBox::warning(0,"警告","开启监听失败.原因:"+m_tcpServer->errorString());
        }
    }else if(ui->btnListen->text() == "关闭监听"){
        ui->combHostType->setEnabled(true);
        ui->combHostAddress->setEnabled(true);
        ui->spinPort->setEnabled(true);
        ui->btnListen->setText("开启监听");
        m_tcpServer->close();
        if(m_tcpSocket->isOpen()){
            m_tcpSocket->disconnect();
            m_tcpSocket->close();
            m_tcpSocket->deleteLater();
        }
        m_tcpSocket = new QTcpSocket(this);
        connect(m_tcpSocket,SIGNAL(errorOccurred(QAbstractSocket::SocketError)),this,SLOT(onTcpSocketError()));
        connect(m_tcpSocket,SIGNAL(connected()),this,SLOT(onTcpSocketConnected()));
        connect(m_tcpSocket,SIGNAL(readyRead()),this,SLOT(onReadyRead()));
        ui->textLog->append("已关闭监听.");
    }else if(ui->btnListen->text() == "连接服务器"){
        m_timer1.start();
        ui->btnListen->setText("正在连接");
        ui->textLog->append("正在尝试连接"+ui->editTargetAddress->text().trimmed()+":"+QString::asprintf("%d",ui->spinPort->value()));
        ui->btnListen->setEnabled(false);
        m_tcpSocket->connectToHost(ui->editTargetAddress->text().trimmed(),ui->spinPort->value());

        ui->combHostType->setEnabled(false);
        ui->editTargetAddress->setEnabled(false);
        ui->spinPort->setEnabled(false);
    }else if(ui->btnListen->text() == "断开连接"){
        ui->btnListen->setText("连接服务器");
        ui->combHostType->setEnabled(true);
        ui->editTargetAddress->setEnabled(true);
        ui->spinPort->setEnabled(true);
        m_tcpSocket->disconnectFromHost();
        m_tcpSocket->abort();
        ui->textLog->append("已断开连接");
    }
}


void MainWindow::on_btnBrows_clicked()
{
    QString savePath = QFileDialog::getExistingDirectory(0,"选择保存路径",QDir::homePath());
    if(QFile::exists(savePath)){
        ui->editSavePath->setText(savePath);
    }
}


void MainWindow::on_btnUpdate_clicked()
{
    ui->listFiles->clear();
    m_tcpSocket->write(QString("#update").toUtf8()+'\n');

}

void MainWindow::onReadyRead()
{
    for(;m_tcpSocket->canReadLine() || !m_tcpSocket->atEnd();){
        QByteArray rec = m_tcpSocket->readLine();

        QDir dir;
        dir.setPath(ui->editSavePath->text());
        dir.setFilter(QDir::Filter::Files);
        QStringList fileList = dir.entryList();

        if(rec == QString("#update").toUtf8()+'\n'){//刷新模式


            for(int i= 0;i < fileList.count(); ++i){
                m_tcpSocket->write(fileList.at(i).toUtf8()+'\n');
            }
        }else if(rec.length() > 1 && rec.at(0) == '$'){//发送模式
            rec.remove(rec.length()-1,1);
            QStringList fileNameList = QString::fromUtf8(rec).split('$');
            QList<QFile*> fileList;
            for(int i = 0; i < fileNameList.count(); ++i){

                QFile* file = new QFile(ui->editSavePath->text()+'\\'+fileNameList.at(i));
                if(file->open(QIODevice::ReadOnly)){
                    fileList.append(file);

                }
            }

            qint64 fileSize = -1;
            for(int i = 0; i < fileList.count();++i){
                fileSize = fileList.at(i)->size();
                QFileInfo info(*fileList.at(i));
                QString str = "@" + info.fileName() + "@" +QString::asprintf("%lld",fileSize) + "\n";
                m_tcpSocket->write(str.toUtf8());
                while(!fileList.at(i)->atEnd()){

                    QByteArray array = QString('&').toUtf8() + fileList.at(i)->readLine();
                    m_tcpSocket->write(array);

                }
                fileList.at(i)->close();
            }


        }else if(rec.length() > 1 && rec.at(0) == '@'){//单个文件下载模式
            rec.remove(rec.length()-1,1);
            QStringList alist = QString::fromUtf8(rec).split('@');//此处未处理好字符串,导致出现三个字符串,第一个为空,第二个为文件名,第三个为文件大小
            QString fileName = alist.at(1);
            m_fileSize= alist.at(2).toLongLong();

            m_file = new QFile(ui->editSavePath->text()+'/'+fileName);
            if(m_file->open(QIODevice::WriteOnly)){
                ui->textLog->append(fileName+"开始接收.一共:"+QString::asprintf("%lld",m_fileSize));
                ui->progressBar->setMaximum(m_fileSize);

            }
        }else if(rec.length() > 1 && rec.at(0) == '&'){//接收数据模式

            rec.remove(0,1);
            if(m_file->isOpen()){

                qint64 size = m_file->write(rec);
                m_getSize += size;
                ui->progressBar->setValue(m_getSize);

                qDebug() << "已下载字节:" << m_getSize;
                    if(m_getSize >= m_fileSize){
                    ui->textLog->append(m_file->fileName()+"下载完成.");
                    m_getSize = 0;
                    m_file->close();
                    m_file->deleteLater();
                }
            }
        }
        else{//接收刷新文件名模式
            rec.remove(rec.length()-1,1);
            QString fName = QString::fromUtf8(rec);
            ui->listFiles->addItem(fName);

            if(fileList.contains(fName)){
                ui->listFiles->item(ui->listFiles->count()-1)->setCheckState(Qt::CheckState::PartiallyChecked);
            }else{
                ui->listFiles->item(ui->listFiles->count()-1)->setCheckState(Qt::CheckState::Unchecked);
            }
        }
    }
}


void MainWindow::on_btnDownload_clicked()
{
    QString requestStr;
    requestStr += '$';
    for(int i = 0; i < ui->listFiles->count();++i){
        if(ui->listFiles->item(i)->checkState() == Qt::CheckState::Checked){
            requestStr +='$';
            requestStr += ui->listFiles->item(i)->text();
        }
    }
    requestStr += '$';
    requestStr += '\n';
    m_tcpSocket->write(requestStr.toUtf8());

}

